package com.ruoyi.web.controller.charge;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.charge.clinet.ChargingPileVerticle;
import com.ruoyi.charge.domain.Charger;
import com.ruoyi.charge.domain.ChargerGun;
import com.ruoyi.charge.dto.ChargerGunStatusDto;
import com.ruoyi.charge.manager.ChargingPileManager;
import com.ruoyi.charge.model.ChargingPile;
import com.ruoyi.charge.protocol.IClientService;
import com.ruoyi.charge.service.IChargerGunService;
import com.ruoyi.charge.service.IChargerService;
import com.ruoyi.common.constants.CacheConstant;
import com.ruoyi.common.enums.EYn;
import com.ruoyi.common.utils.RedisUtil;
import com.ruoyi.common.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.*;
import org.noear.solon.core.handle.Result;

/**
 * 充电桩核心操作处理
 *
 * @author ruoyi
 */
@Controller
@Mapping("core")
@Api("充电桩操作")
@Slf4j
public class ChargeCoreController extends BaseController {

    @Inject
    private IChargerService chargerService;
    @Inject
    private Vertx vertx; // 注入 Vert.x 实例
    @Inject
    private RedisUtil redisUtil;
    @Inject
    private IChargerGunService chargerGunService;
    @Inject
    private IClientService clientService;
    @Inject
    private ChargingPileManager chargingPileManager;


    /**
     * 连接充电桩并模拟上电
     */
    @Get
    @Mapping("connect")
    @ApiOperation("连接上电")
    public Result connect(Long id) {
        Charger charger = chargerService.getById(id);
        if (charger == null) {
            return Result.failure("充电桩不存在");
        }

        // 使用 Future.compose() 构建完整的异步链
        redeployChargerVerticle(charger);
        return Result.succeed("开始连接...");
    }

    /**
     * 下电
     */
    @Get
    @Mapping("disconnect")
    @ApiOperation("下电")
    public Result disconnect(Long id) {
        Charger charger = chargerService.getById(id);
        if (charger == null) {
            return Result.failure("充电桩不存在");
        }

        // 使用 Future.compose() 构建完整的异步链
        getOldDeploymentId(charger.getSn())
                .compose(deploymentIdOld -> {
                    if (StrUtil.isNotEmpty(deploymentIdOld)) {
                        // 如果存在旧部署，先卸载
                        return undeployOldVerticle(deploymentIdOld)
                                .onSuccess(v -> {
                                    chargerGunService.setChargerGunOfflineByChargerSn(charger.getSn());
                                });
                    }
                    return null;
                });
        return Result.succeed("开始下电...");
    }


    /**
     * 插枪
     */
    @Post
    @Mapping("insertGun")
    @ApiOperation("插枪")
    public Result insertGun(Long id, Long gunId) {
        Charger charger = chargerService.getById(id);
        if (charger == null) {
            return Result.failure("充电桩不存在");
        }
        ChargerGun chargerGun = chargerGunService.getById(gunId);
        if (chargerGun == null) {
            return Result.failure("充电枪不存在");
        }
        ChargingPile chargingPile = chargingPileManager.getChargingPile(charger.getSn());
        if (chargingPile == null) {
            return Result.failure("充电桩未连接");
        }
        // 更新充电桩状态
        chargerGun.setIsInsert(1);
        chargerGunService.updateById(chargerGun);
        ChargerGunStatusDto gunStatusDto = BeanUtil.copyProperties(chargerGun, ChargerGunStatusDto.class);
        gunStatusDto.setChargerSn(charger.getSn());
        gunStatusDto.setGunNo(chargerGun.getNumber());
        gunStatusDto.setIsChange(EYn.YES);
        clientService.uploadRealTimeData(chargingPile.getSocket(), gunStatusDto);

        return Result.succeed();
    }

    /**
     * 拔枪
     */
    @Post
    @Mapping("removeGun")
    @ApiOperation("拔枪")
    public Result removeGun(Long id, Long gunId) {
        Charger charger = chargerService.getById(id);
        if (charger == null) {
            return Result.failure("充电桩不存在");
        }
        ChargerGun chargerGun = chargerGunService.getById(gunId);
        if (chargerGun == null) {
            return Result.failure("充电枪不存在");
        }
        ChargingPile chargingPile = chargingPileManager.getChargingPile(charger.getSn());
        if (chargingPile == null) {
            return Result.failure("充电桩未连接");
        }
        // 更新充电桩状态
        chargerGun.setIsInsert(0);
        chargerGunService.updateById(chargerGun);
        ChargerGunStatusDto gunStatusDto = BeanUtil.copyProperties(chargerGun, ChargerGunStatusDto.class);
        gunStatusDto.setIsChange(EYn.YES);
        gunStatusDto.setChargerSn(charger.getSn());
        gunStatusDto.setGunNo(chargerGun.getNumber());
        clientService.uploadRealTimeData(chargingPile.getSocket(), gunStatusDto);

        return Result.succeed();
    }


    // --------------------------------------private方法--------------------------------------

    /**
     * 重新部署充电桩
     */
    private void redeployChargerVerticle(Charger charger) {
        getOldDeploymentId(charger.getSn())
                .compose(deploymentIdOld -> {
                    if (StrUtil.isNotEmpty(deploymentIdOld)) {
                        // 如果存在旧部署，先卸载
                        return undeployOldVerticle(deploymentIdOld)
                                .compose(v -> deployNewVerticle(charger));
                    } else {
                        // 如果没有旧部署，直接部署新 verticle
                        return deployNewVerticle(charger);
                    }
                })
                .onSuccess(deploymentId -> {
                    // 部署成功后，将新的 deploymentId 存入 Redis
                    saveDeploymentId(charger.getSn(), deploymentId)
                            .onSuccess(v -> {
                            })
                            .onFailure(throwable -> {
                            });
                })
                .onFailure(throwable -> log.error("连接充电桩失败：{}", throwable.getMessage()));
    }

    // 获取旧的部署ID
    private Future<String> getOldDeploymentId(String sn) {
        return Future.future(promise -> {
            try {
                String deploymentId = Convert.toStr(redisUtil.hGet("deployVerticle", sn));
                promise.complete(deploymentId);
            } catch (Exception e) {
                promise.fail("获取旧部署ID失败：" + e.getMessage());
            }
        });
    }


    // 卸载旧的 verticle
    private Future<Void> undeployOldVerticle(String deploymentId) {
        return Future.future(promise -> vertx.undeploy(deploymentId)
                .onSuccess(v -> {
                    log.info("成功卸载旧的 verticle: {}", deploymentId);
                    promise.complete(v);
                    // 删除缓存
                })
                .onFailure(throwable -> {
                    log.warn("卸载旧的 verticle 失败: {}, {}", deploymentId, throwable.getMessage());
                    // 即使卸载失败也继续部署新的，避免因为旧部署残留导致无法部署
                    promise.complete(); // 不要用 fail，让流程继续
                }));
    }

    // 部署新的 verticle
    private Future<String> deployNewVerticle(Charger charger) {
        return Future.future(promise -> {
            ChargingPileVerticle verticle = new ChargingPileVerticle(
                    charger.getSn(),
                    charger.getServerIp(),
                    charger.getServerPort()
            );

            vertx.deployVerticle(verticle)
                    .onSuccess(deploymentId -> {
                        log.info("成功部署新的 verticle: {}, SN: {}", deploymentId, charger.getSn());
                        promise.complete(deploymentId);
                    })
                    .onFailure(throwable -> {
                        log.error("部署新的 verticle 失败, SN: {}", charger.getSn(), throwable);
                        promise.fail("部署新的 verticle 失败：" + throwable.getMessage());
                    });
        });
    }

    // 保存部署ID到Redis
    private Future<Void> saveDeploymentId(String sn, String deploymentId) {
        return Future.future(promise -> {
            try {
                redisUtil.hSet(CacheConstant.deployVerticleKey, sn, deploymentId);
                promise.complete();
            } catch (Exception e) {
                promise.fail("保存部署信息到Redis失败：" + e.getMessage());
            }
        });
    }
}